package com.example.demo.aspect;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

@Aspect
@Component
public class LogAspect {
    private final Logger logger = LoggerFactory.getLogger(LogAspect.class);
    private final ObjectMapper objectMapper = new ObjectMapper();

    // 定义切点
    @Pointcut("execution(* com.example.demo.service..*.*(..))")
    public void serviceLog() {}

    @Pointcut("execution(* com.example.demo.controller..*.*(..))")
    public void controllerLog() {}

    // 在方法执行前打印入参
    @Before("serviceLog() || controllerLog()")
    public void doBefore(JoinPoint joinPoint) {
        try {
            // 获取请求信息
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            if (attributes != null) {
                HttpServletRequest request = attributes.getRequest();
                logger.info("URL: {}", request.getRequestURL().toString());
                logger.info("HTTP Method: {}", request.getMethod());
                logger.info("IP: {}", request.getRemoteAddr());
            }

            // 打印类名和方法名
            logger.info("Class Method: {}.{}", 
                joinPoint.getSignature().getDeclaringTypeName(),
                joinPoint.getSignature().getName());

            // 打印请求参数
            logger.info("Request Args: {}", 
                objectMapper.writeValueAsString(Arrays.asList(joinPoint.getArgs())));
        } catch (Exception e) {
            logger.error("Error logging before method execution", e);
        }
    }

    // 环绕通知，打印执行时间和返回值
    @Around("serviceLog() || controllerLog()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        
        Object result = proceedingJoinPoint.proceed();
        
        // 打印出参
        try {
            logger.info("Response Args: {}", 
                result != null ? objectMapper.writeValueAsString(result) : null);
        } catch (Exception e) {
            logger.error("Error logging response", e);
        }

        // 打印执行时间
        long endTime = System.currentTimeMillis();
        logger.info("Time-Consuming: {} ms", (endTime - startTime));
        
        return result;
    }

    // 异常通知
    @AfterThrowing(pointcut = "serviceLog() || controllerLog()", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Throwable e) {
        logger.error("Method {} threw exception: {}", 
            joinPoint.getSignature().getName(), 
            e.getMessage());
    }
} 